/** \brief Fichier implémentant le mécanisme de sortie.
 *
 * Ce fichier contient l'implémentation des objets nécessaires pour une sortie
 * paramétrable.
 *
 * @file FlotMessage.cc
 * @author Johan "Solo" Luisier
 * @date Mai 2010
 */
#include "FlotMessage.h"

#include <iostream>

#include <boost/assign/list_of.hpp>

using namespace std;
using namespace boost::assign;

/** \brief Objet utilisé comme objet statique.
 *
 * Est utilisé lorsque la sortie est nécessaire à l'extérieur d'une classe
 * possédant un accès à une instance de FlotMessage.
 */
FlotMessage FlotMessageGlobal( BLANK );

FlotMessage& flotMessageGlobal()
{
    return FlotMessageGlobal;
}

bool FlotMessage::UtiliseCouleur( true );

const map< DebugLevelType, CColor > FlotMessage::Decorations =
        map_list_of
        ( ALL     , CColor( DEFAULT_COLOR, DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( MEM     , CColor( DEFAULT_COLOR, DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( DEBUG   , CColor( CYAN         , DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( LFUNC   , CColor( GREEN        , DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( LINFO   , CColor( YELLOW       , DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( FUNC    , CColor( BLUE         , DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( INFO    , CColor( DEFAULT_COLOR, DEFAULT_COLOR, ATTRIB_ITALIC ) )
        ( BLANK   , CColor( DEFAULT_COLOR, DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( PROGRESS, CColor( DEFAULT_COLOR, DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( RELEASE , CColor( DEFAULT_COLOR, DEFAULT_COLOR, ATTRIB_NONE   ) )
        ( WARN    , CColor( RED          , DEFAULT_COLOR, ATTRIB_BOLD   ) )
        ( ERR     , CColor( WHITE        , RED          , ATTRIB_BOLD   ) );

const map< DebugLevelType, string > FlotMessage::Textes =
        map_list_of
        ( ALL     , "ALL" )
        ( MEM     , "MEM" )
        ( DEBUG   , "DEBUG" )
        ( LFUNC   , "LFUNC" )
        ( LINFO   , "LINFO" )
        ( FUNC    , "FUNC" )
        ( INFO    , "INFO" )
        ( BLANK   , "BLANK" )
        ( PROGRESS, "PROGRESS" )
        ( RELEASE , "RELEASE" )
        ( WARN    , "WARN" )
        ( ERR     , "ERR" );

FlotMessage::FlotMessage( const DebugLevelType& level, const string& source )
    : Source( source ), NiveauCourant( BLANK ), NiveauInstance( level )
{}

FlotMessage::FlotMessage( const FlotMessage& flot )
    : Source( flot.Source ), NiveauCourant( flot.NiveauCourant ),
      NiveauInstance( flot.NiveauInstance )
{
    Stream.str( flot.Stream.str() );
    //str( flot.str() );
}

FlotMessage::~FlotMessage()
{}

ostringstream& FlotMessage::stream()
{
    return Stream;
}

void FlotMessage::setNiveauCourant( const DebugLevelType& level )
{
    *this << level;
}

const DebugLevelType& FlotMessage::niveauCourant() const
{
    return NiveauCourant;
}

void FlotMessage::setNiveauInstance( const DebugLevelType& level )
{
    NiveauInstance = level;
}

const DebugLevelType& FlotMessage::niveauInstance() const
{
    return NiveauInstance;
}

void FlotMessage::setUtiliseCouleur( const bool& utilCouleur )
{
    UtiliseCouleur = utilCouleur;
}

const bool& FlotMessage::utiliseCouleur()
{
    return UtiliseCouleur;
}

const bool& FlotMessage::estActif() const
{
    return EstActif;
}

FlotMessage& FlotMessage::produireSortie( const Manipulateur& manip )
{
    try
    {
        if ( estActif() )
        {
            if ( utiliseCouleur() )
                cout << Decorations.find( NiveauCourant ) -> second . colorCode();
            if ( NiveauCourant != BLANK )
                cout << setw( 20 ) << left << Source << setw( 10 )
                     << left << Textes.find( NiveauCourant ) -> second;
            cout << Stream.str();
            if ( utiliseCouleur() )
                cout << "\033[0m";
            switch ( manip )
            {
            case FinDeLigne:
                cout << endl;
            case AffichageSimple:
                cout << flush;
                break;
            }
        }

        Stream.str( "" );
    }
    catch( exception& e )
    {
        cerr << "Exception : " << e.what() << endl;
    }
    return *this;
}

FlotMessage& FlotMessage::operator<<( const DebugLevelType& level )
{
    if ( level < niveauInstance() )
        desactiver();
    else
        activer();

    if ( level != NiveauCourant )
    {
        if ( utiliseCouleur() )
        {
            try
            {
                Stream << Decorations.find( level ) -> second . colorCode();
            }
            catch ( ... )
            {}
        }
        NiveauCourant = level;
    }
    return *this;
}

FlotMessage& FlotMessage::operator<<( const Manipulateur& manip )
{
    return produireSortie( manip );
}

void FlotMessage::activer()
{
    EstActif = true;
}

void FlotMessage::desactiver()
{
    EstActif = false;
}
